package com.gz.EuchreU.Contants;

import java.util.ArrayList;
import java.util.Random;

import android.util.Log;

import com.gz.EuchreU.Helpers.Player;
import com.gz.EuchreU.Sprite.Card;

public class GameState {
	
	public final static int INITIALIZING	= -1;
	public final static int SHUFFLING 		= 0;
	public final static int DEALING 		= SHUFFLING + 1;
	public final static int TURN_CARD_UP	= DEALING + 1;
	public final static int TURN_CARD_DOWN	= TURN_CARD_UP + 1;
	public final static int DISCARDING		= TURN_CARD_DOWN + 1;
	public final static int TRUMP_CALLED	= DISCARDING + 1;
	public final static int PLAYING_TRICKS	= TRUMP_CALLED + 1;
	public final static int SHOW_WINNER		= PLAYING_TRICKS + 1;
	public final static int NEXT_DEALER		= SHOW_WINNER + 1;
	
	public final static int TRICK_FIRST			= 0;
	public final static int TRICK_SECOND		= TRICK_FIRST + 1;
	public final static int TRICK_THIRD			= TRICK_SECOND + 1;
	public final static int TRICK_FOURTH		= TRICK_THIRD + 1;
	public final static int TRICK_LAST			= TRICK_FOURTH + 1;
	
	public final static int PLAYER_NORTH	= 0;
	public final static int PLAYER_EAST		= PLAYER_NORTH + 1;
	public final static int PLAYER_SOUTH	= PLAYER_EAST + 1;
	public final static int PLAYER_WEST		= PLAYER_SOUTH + 1;
	
	private static int mGameState;
	private static int mCurDealer;
	private static int mCurPlayer;
	private static int mCurTrick;
	private static int mOrderedUpPlayerID	= -1;
	private static int mDealingCardIndex = 0;
	private static Card mTurnCard;
	private static Player[] mPlayers = new Player[4];
	private static Card[][] mHandTricks = new Card[5][4];
	private static int[] mLeadPlayerID = new int[5];
	private static int[] mShuffledIndicies;
	private static Card[] mKitty = new Card[3];
	private static boolean mAlone = false;
	
	private static ArrayList<Card> mCards = new ArrayList<Card>();
	
	public static void ResetAll(){
		
		ClearCards();
		InitPlayers();
		ResetTricks();
		ResetDealingIndex();
		mLeadPlayerID = new int[5];
		mShuffledIndicies = GetShuffledIndecies();
		mTurnCard = null;
		mDealingCardIndex = 0;
		mOrderedUpPlayerID	= -1;
		mAlone = false;
		mCurTrick = 0;
		mCurPlayer = 0;
		mCurDealer = 0;
		mGameState = INITIALIZING;
		
		CardValues.ResetAll();
		
		Suits.setTrump(Suits.NONE);
		
	}
	
	public static void InitPlayers(){
		for (int i = 0; i < 4; i++) {
			if(mPlayers[i] == null){
			mPlayers[i] = new Player(i);
			}
		}
	}
	
	public static float getDealIdleTime(){
		float flReturn = 0;
		
		switch(GameOptions.GetIntOption(GameOptions.PREF_INT_GAME_SPEED)){
		case 0:
			flReturn = .75f;
			break;
		case 1:
			flReturn = .4f;
			break;
		case 2:
			flReturn = .25f;
			break;
		case 3:
			flReturn = .15f;
			break;
		default:
			flReturn = 0;
			break;
		}
		
		log("Deal idle time: " + flReturn);
		
		return flReturn;
	}
	
	public static int getGameState(){
		return mGameState;
	}
	
//	public static int getCurrentDealer(){
//		return mCurDealer;
//	}
	
	public static int getDealer(){
	return mCurDealer;
}
	
	public static int getCurrentPlayer(){
		return mCurPlayer;
	}
	
	public static void Shuffle(){
		NextDealer();
		ResetDealingIndex();
		for(Player p : GetPlayers()){
			p.Clear();
		}
		
		for (int i = 0; i < GetCards().size(); i++) {
			GetCards().get(i).Reset();
			GetCards().get(i).MoveToShuffle(CardLocations.GetPlayerCardLocation(getDealer()));
		}
		
		setState(SHUFFLING);
	}
	
	public static void setState(int pGameState){
		mGameState = pGameState;
		
		switch (mGameState) {
		case DEALING:
			ResetDealingIndex();
			ShuffleIndecies(24);
			
			break;
		case PLAYING_TRICKS:
			ResetTricks();
			setDealer(mCurDealer);
			break;
		case SHOW_WINNER:
			Suits.setTrump(-1);
			ResetTricks();
		default:
			break;
		}
	}
	
	public static int[] GetShuffledIndecies(){
		if(mShuffledIndicies == null){
			ShuffleIndecies(24);
		}
		return mShuffledIndicies;
	}
	
	public static void ShuffleIndecies(int pCount){
		Random rand = new Random();
		mShuffledIndicies = new int[pCount];
		ArrayList<Integer> lst = new ArrayList<Integer>();
		
		for (int i = 0; i < mShuffledIndicies.length; i++) {
			int newRandom = rand.nextInt(pCount);
			while(lst.contains(newRandom)){
				newRandom = rand.nextInt(pCount);
			}
			
			mShuffledIndicies[i] = newRandom;
			lst.add(newRandom);
		}
	}
	
	public static int GetDealingIndex(){
		return mDealingCardIndex;
	}
	
	public static void AddToDealingIndex(){
		mDealingCardIndex++;
	}
	
	public static void ResetDealingIndex(){
		mDealingCardIndex = 0;
	}
	
	public static ArrayList<Card> GetCards(){
		return mCards;
	}
	
	public static void ClearCards(){
		log("Clearing cards");
		mCards.clear();
	}
		
	public static Card AddCard(float pX, float pY, int pSuitID, int pValueID)
	{
		Card card = new Card(pX, pY, pSuitID, pValueID);
		AddCard(card);
		return card;
	}
	
	public static void AddCard(Card card){
		mCards.add(card);
		log("Adding card " + mCards.size() + " - " + card.ToString());
	}
	
	public static int NextDealer(){
		log("Next dealer");
		switch (mCurDealer) {
		case PLAYER_NORTH:
		case PLAYER_EAST:
		case PLAYER_SOUTH:
			mCurDealer++;
			break;
		default:
			mCurDealer = PLAYER_NORTH;
			break;
		}
		
		setCurrentPlayer(mCurDealer);
		NextPlayer();
		
		return mCurDealer;
	}
	
	public static int DealNextPlayer(){
		log("DealNextPlayer");
		return NextPlayer();
	}
	
	private static int NextPlayer(){
		log("Next Player");
		if(IsTrickOver()){
			log("Next Player - Trick is over...");
			OnTrickOver();
		}
		else{
			int test = mCurPlayer%4;
			log("Next Player " + mCurPlayer + "-" + test);
			
			
			switch (mCurPlayer%4) {
			case PLAYER_NORTH:
			case PLAYER_EAST:
			case PLAYER_SOUTH:
				setCurrentPlayer(mCurPlayer+1);
				break;
			default:
				setCurrentPlayer(PLAYER_NORTH);
				break;
			}
		}
		return mCurPlayer;
	}
	
	public static void SetTurnCard(Card pCard){
		log("Turn card set to " + pCard.ToString());
		mTurnCard = pCard;
	}
	
	public static void setKitty(Card pCard, int id){
		mKitty[id] = pCard;
	}
	
	public static boolean IsGoingAlone(){
		return mAlone;
	}
	
	public static boolean IsTrickOver(){
		if(IsGoingAlone() && GetCurrentTrickCount() == 3){
			log("Loner. Have 3 cards hand is over");
			return true;
		}
		else if(GetCurrentTrickCount() == 4){
			log("Trick count is 4... hand is over");
			return true;
		}
		else return false;
	}
	
	public static void setCurrentPlayer(int pPlayerID){
		switch (pPlayerID) {
		case PLAYER_NORTH:
		case PLAYER_EAST:
		case PLAYER_SOUTH:
		case PLAYER_WEST:
			mCurPlayer = pPlayerID;
			break;
		default:
			mCurPlayer = PLAYER_NORTH;
			break;
		}
		
		if(IsGoingAlone() && GetPlayers()[pPlayerID].IsPartner(GetOrderedPlayerID())){
			//Partner is going alone...
			//Next!
			NextPlayer();
		}
		
		if(GetCurrentTrickCount() == 0 && getGameState() == PLAYING_TRICKS){
			log("Setting Lead Card. 0 cards in trick");
			SetLeadCard(mCurPlayer);
		}
	}
	
	private static void SetLeadCard(int pLeader){
		mLeadPlayerID[mCurTrick] = pLeader;
		
		//mLeader = pLeader;
		log("Leader set:" + pLeader);
	}
	
	public static void setDealer(int pPlayerID){
		log("Set Dealer: " + pPlayerID);
		switch (pPlayerID) {
		case PLAYER_NORTH:
		case PLAYER_EAST:
		case PLAYER_SOUTH:
		case PLAYER_WEST:
			mCurDealer = pPlayerID;
			break;
		default:
			mCurDealer = PLAYER_NORTH;
			break;
		}
		
		mCurPlayer = mCurDealer;
		NextPlayer();
	}
	
	public static boolean IsHuman(int pPlayerID){
		switch (pPlayerID) {
		case PLAYER_SOUTH:
			return true;
		default:
			return false;
		}
	}

	public static Player[] GetPlayers(){
		return mPlayers;
	}
	
	public static int GetOrderedPlayerID(){
		return mOrderedUpPlayerID;
	}
	
	public static void PickUp(boolean pAlone){
		//mPlayers[mCurrentDealer].AddCard()
		mAlone = pAlone;
		log("Pickup Called");
		mOrderedUpPlayerID = getCurrentPlayer();
		Suits.setTrump(GetTurnCard().GetSuitID());
		setState(DISCARDING);
		setCurrentPlayer(getDealer());
		GetPlayers()[getDealer()].AddCard(GetTurnCard());
		log("Waiting for discard");
	}
	
	public static void CallSuit(int pSuitID, boolean pAlone){
		mAlone = pAlone;
		mOrderedUpPlayerID = getCurrentPlayer();
		Suits.setTrump(pSuitID);
		setState(TRUMP_CALLED);
	}
	
	public static void Pass(){
		log("Pass called in GameState");
		if(getCurrentPlayer() == getDealer()){
			if(getGameState() == TURN_CARD_UP){
				setState(TURN_CARD_DOWN);
				GetTurnCard().MoveToDiscard();
			}
			else if (getGameState() == TURN_CARD_DOWN){
				if(!GameOptions.GetBoolOption(GameOptions.PREF_BOOL_STD)){
					setState(SHOW_WINNER);
				}
			}
		}
		NextPlayer();
	}
	
	public static void Discard(){
		GetPlayers()[getDealer()].OrganizeHand();
		GameState.setState(GameState.TRUMP_CALLED);
	}
	
	public static void StartPlayingTricks(){
		for (int i = 0; i < mKitty.length; i++) {
			if(mKitty[i] != null){
				mKitty[i].MoveToDiscard();
			}
		}
		
		setState(PLAYING_TRICKS);
	}
	
	private static void AddCardToTrick(Card pCard){
		mHandTricks[mCurTrick][getCurrentPlayer()] = pCard;
	}
	
	public static void ResetTricks(){
		mHandTricks = new Card[5][4];
		setTrick(TRICK_FIRST);
	}
	
	public static Card[] GetCurrentTrick(){
		return mHandTricks[mCurTrick];
	}
	
	public static Card[][] GetAllTricks(){
		return mHandTricks;
	}
	
	public static Card GetLeadCard(){
		return GetCurrentTrick()[GetCurrentLeader()];
	}
	
	public static Card GetLeadCard(int pTrickID){
		return GetAllTricks()[pTrickID][GetTrickLeader(pTrickID)];
	}
	
	public static Card[] GetAllLeadCards(){
		Card[] cardsReturn = new Card[5];
		for (int i = 0; i < cardsReturn.length; i++) {
			cardsReturn[i] = GetLeadCard(i);
		}
		return cardsReturn;
	}
	
	public static int GetCurrentLeader(){
		return GetTrickLeader(mCurTrick);
	}
		
	public static int GetTrickLeader(int pTrickID){
		return mLeadPlayerID[pTrickID];
	}
	
	public static int GetCurrentTrickCount(){
		int intReturn = 0;
		for (int i = 0; i < 4; i++) {
			if(GetCurrentTrick()[i] != null)intReturn++;	
		}
		
		log("CurrentTrickCount: " + intReturn);
		return intReturn;
	}
	
	public static int GetPlayerWinningTrick(){
		Card rCard = null;
		int intReturn = -1;
		for (int i = 0; i < GetCurrentTrick().length; i++) {
			if(GetCurrentTrick()[i] != null){
				if(rCard == null){
					rCard = GetCurrentTrick()[i];
					intReturn = i; 
				}
				else if(GetCurrentTrick()[i].GetCardHandValue() > rCard.GetCardHandValue()){
					rCard = GetCurrentTrick()[i];
					intReturn = i;
				}
			}
		}
		
		return intReturn;
	}

	public static Card GetTurnCard(){
		return mTurnCard;
	}

	public static void OnTrickOver(){
		for (Card card : GetCurrentTrick()) {
			if(card != null){
				card.MoveToDiscard();
			}
		}
		int winner = GetTrickWinner();
		mPlayers[winner].AddTrickWon();
		
		if(mCurTrick == TRICK_LAST){
			OnHandOver();
		}
		else NextTrick();
				
		setCurrentPlayer(winner);
	}
	
	public static void NextTrick(){
		setTrick(mCurTrick+1);
	}
	
	public static int GetTrickWinner(){
		int highWinnerID = -1;
		int highValue = -1;
		for (int i = 0; i < GetCurrentTrick().length; i++) {
			if(GetCurrentTrick()[i] != null){
				int cardValue = GetCurrentTrick()[i].GetCardHandValue();
				log("Checking " + GetCurrentTrick()[i].ToString() + " value = " + cardValue);
				if(cardValue > highValue){
					highValue = cardValue;
					highWinnerID = i;
					log("High card = " + GetCurrentTrick()[i].ToString());
				}
			}
		}
		log("Trick Winner: " + highWinnerID);
		return highWinnerID;
	}
	

	public static void setTrick(int pTrickID){
		switch (pTrickID) {
		case TRICK_FIRST:
		case TRICK_SECOND:
		case TRICK_THIRD:
		case TRICK_FOURTH:
		case TRICK_LAST:
			mCurTrick = pTrickID;
			break;
		default:
			mCurTrick = TRICK_FIRST;
			break;
		}
	}

	
	public static void OnHandOver(){
		mAlone = false;
		
		if(GetRedTricks() > GetBlueTricks()){
			if(mOrderedUpPlayerID%2 == 0){
				//we ordered up
				if(GameState.IsGoingAlone()){
					if(GetRedTricks() == 5){
						CardValues.AddScoreRed(4);
					}
					else
					{
						CardValues.AddScoreRed(1);
					}
				}
				else{
					if(GetRedTricks() == 5)CardValues.AddScoreRed(2);
					else CardValues.AddScoreRed(1);
				}
				
			}
			else{
				CardValues.AddScoreRed(2);
			}
			
			
			
			//TODO: ALONE/EUCHRE
		}
		else{
			if(mOrderedUpPlayerID%2 == 1){
				if(IsGoingAlone()){
					if(GetBlueTricks() == 5){
						CardValues.AddScoreBlue(4);
					}
					else{
						CardValues.AddScoreBlue(1);
					}
				}
				else{
					
					if(GetBlueTricks() == 5)CardValues.AddScoreBlue(2);
					else CardValues.AddScoreBlue(1);
				}
				
			}
			else{
				CardValues.AddScoreBlue(2);
			}
		}
		
		
		
		setState(SHOW_WINNER);
	}
	
	public static boolean IsHandDecidedEarly(){
		if(GetRedTricks() == 3 && GetBlueTricks() == 1){
			return true;
		}
		else if(GetBlueTricks() == 3 && GetRedTricks() == 1){
			return true;
		}
		else return false;
	}
	
	public static String GetTrickString(){
		String strReturn = "Current Trick - ";
		
		for (int i = 0; i < GetCurrentTrick().length; i++) {
			if(GetCurrentTrick()[i] == null){
				strReturn += "null";
			}
			else strReturn += GetCurrentTrick()[i].ToShortString();
			
			if(i < GetCurrentTrick().length - 1)strReturn += "_";
		}
		
		return strReturn;
	}
	
	public static int PlayCard(Card pCard){
		log("Play card " + pCard.ToString());
		AddCardToTrick(pCard);
		return NextPlayer();
	}
	
	public static int GetRedTricks(){
		return mPlayers[0].GetTrickCount() + mPlayers[2].GetTrickCount();
	}
	
	public static int GetBlueTricks(){
		return mPlayers[1].GetTrickCount() + mPlayers[3].GetTrickCount();
	}
	
	public static void LogState(String msg){
		log(msg);
	}
	
	private static void log(String msg){
		Log.d("GS-S:" + getGameState() + "T" + mCurTrick +  "D" + mCurDealer + "P" + getCurrentPlayer() + "TR" + Suits.getTrumpID() + "",msg);
	}
	
}
